{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mt9dL5dIir8X"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "ufPx7EiCiqgR"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ucMoYase6URl"
      },
      "source": [
        "# 이미지 로드"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_Wwu5SXZmEkB"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/load_data/images\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/tutorials/load_data/images.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/tutorials/load_data/images.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub에서 소스 보기</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/tutorials/load_data/images.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Oxw4WahM7DU9"
      },
      "source": [
        "이 튜토리얼은 두 가지 방법으로 이미지 데이터세트를 로드하고 전처리하는 방법을 보여줍니다. 먼저, 고급 Keras 전처리 [유틸리티](https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image_dataset_from_directory) 및 [레이어](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing)를 사용합니다. 다음으로 [tf.data](https://www.tensorflow.org/guide/data)를 사용하여 처음부터 자체 입력 파이프라인을 작성합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hoQQiZDB6URn"
      },
      "source": [
        "## 설정"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3vhAMaIOBIee"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import os\n",
        "import PIL\n",
        "import PIL.Image\n",
        "import tensorflow as tf\n",
        "import tensorflow_datasets as tfds"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Qnp9Z2sT5dWj"
      },
      "outputs": [],
      "source": [
        "print(tf.__version__)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wO0InzL66URu"
      },
      "source": [
        "### 꽃 데이터세트 다운로드하기\n",
        "\n",
        "이 튜토리얼에서는 수천 장의 꽃 사진 데이터세트를 사용합니다. 꽃 데이터세트에는 클래스당 하나씩 5개의 하위 디렉토리가 있습니다.\n",
        "\n",
        "```\n",
        "flowers_photos/\n",
        "  daisy/\n",
        "  dandelion/\n",
        "  roses/\n",
        "  sunflowers/\n",
        "  tulips/\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ju2yXtdV5YaT"
      },
      "source": [
        "참고: 모든 이미지에는 CC-BY 라이선스가 있으며 크리에이터는 LICENSE.txt 파일에 나열됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rN-Pc6Zd6awg"
      },
      "outputs": [],
      "source": [
        "import pathlib\n",
        "dataset_url = \"https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz\"\n",
        "data_dir = tf.keras.utils.get_file(origin=dataset_url, \n",
        "                                   fname='flower_photos', \n",
        "                                   untar=True)\n",
        "data_dir = pathlib.Path(data_dir)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rFkFK74oO--g"
      },
      "source": [
        "다운로드한 후 (218MB), 이제 꽃 사진의 사본을 사용할 수 있습니다. 총 3670개의 이미지가 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QhewYCxhXQBX"
      },
      "outputs": [],
      "source": [
        "image_count = len(list(data_dir.glob('*/*.jpg')))\n",
        "print(image_count)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZUFusk44d9GW"
      },
      "source": [
        "각 디렉토리에는 해당 유형의 꽃 이미지가 포함되어 있습니다. 다음은 장미입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "crs7ZjEp60Ot"
      },
      "outputs": [],
      "source": [
        "roses = list(data_dir.glob('roses/*'))\n",
        "PIL.Image.open(str(roses[0]))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oV9PtjdKKWyI"
      },
      "outputs": [],
      "source": [
        "roses = list(data_dir.glob('roses/*'))\n",
        "PIL.Image.open(str(roses[0]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9_kge08gSCan"
      },
      "source": [
        "## keras.preprocessing을 사용하여 로드하기\n",
        "\n",
        "[image_dataset_from_directory](https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image_dataset_from_directory)를 사용하여 이들 이미지를 디스크에 로드해 보겠습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eRACclAfOPYR"
      },
      "source": [
        "참고: 이 섹션에 소개된 Keras Preprocesing 유틸리티 및 레이어는 현재 실험 중이며 변경될 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6jobDTUs8Wxu"
      },
      "source": [
        "### 데이터세트 만들기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lAmtzsnjDNhB"
      },
      "source": [
        "로더를 위해 일부 매개변수를 정의합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qJdpyqK541ty"
      },
      "outputs": [],
      "source": [
        "batch_size = 32\n",
        "img_height = 180\n",
        "img_width = 180"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ehhW308g8soJ"
      },
      "source": [
        "모델을 개발할 때 검증 분할을 사용하는 것이 좋습니다. 훈련에 이미지의 80%를 사용하고 검증에 20%를 사용합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "chqakIP14PDm"
      },
      "outputs": [],
      "source": [
        "train_ds = tf.keras.preprocessing.image_dataset_from_directory(\n",
        "  data_dir,\n",
        "  validation_split=0.2,\n",
        "  subset=\"training\",\n",
        "  seed=123,\n",
        "  image_size=(img_height, img_width),\n",
        "  batch_size=batch_size)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pb2Af2lsUShk"
      },
      "outputs": [],
      "source": [
        "val_ds = tf.keras.preprocessing.image_dataset_from_directory(\n",
        "  data_dir,\n",
        "  validation_split=0.2,\n",
        "  subset=\"validation\",\n",
        "  seed=123,\n",
        "  image_size=(img_height, img_width),\n",
        "  batch_size=batch_size)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ug3ITsz0b_cF"
      },
      "source": [
        "이러한 데이터세트의 `class_names` 속성에서 클래스 이름을 찾을 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "R7z2yKt7VDPJ"
      },
      "outputs": [],
      "source": [
        "class_names = train_ds.class_names\n",
        "print(class_names)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bK6CQCqIctCd"
      },
      "source": [
        "### 데이터 시각화하기\n",
        "\n",
        "훈련 데이터세트의 처음 9개 이미지는 다음과 같습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AAY3LJN28Kuy"
      },
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "plt.figure(figsize=(10, 10))\n",
        "for images, labels in train_ds.take(1):\n",
        "  for i in range(9):\n",
        "    ax = plt.subplot(3, 3, i + 1)\n",
        "    plt.imshow(images[i].numpy().astype(\"uint8\"))\n",
        "    plt.title(class_names[labels[i]])\n",
        "    plt.axis(\"off\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jUI0fr7igPtA"
      },
      "source": [
        "이러한 데이터세트를 사용하는 모델을 `model.fit`(이 튜토리얼의 뒷부분에 표시)에 전달하여 모델을 훈련할 수 있습니다. 원하는 경우, 데이터세트를 수동으로 반복하고 이미지 배치를 검색할 수도 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "BdPHeHXt9sjA"
      },
      "outputs": [],
      "source": [
        "for image_batch, labels_batch in train_ds:\n",
        "  print(image_batch.shape)\n",
        "  print(labels_batch.shape)\n",
        "  break"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2ZgIZeXaDUsF"
      },
      "source": [
        "`image_batch`는 형상 `(32, 180, 180, 3)`의 텐서입니다. 이것은 형상 `180x180x3`의 32개 이미지 배치입니다(마지막 치수는 색상 채널 RGB를 나타냄). `label_batch`는 형상 `(32,)`의 텐서이며 32개 이미지에 해당하는 레이블입니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LyM2y47W-cxJ"
      },
      "source": [
        "참고: 이들 텐서 중 하나에서 `.numpy()`를 호출하여 `numpy.ndarray`로 변환할 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ybl6a2YCg1rV"
      },
      "source": [
        "### 데이터 표준화하기\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IdogGjM2K6OU"
      },
      "source": [
        "RGB 채널 값은 `[0, 255]` 범위에 있습니다. 신경망에는 이상적이지 않습니다. 일반적으로 입력 값을 작게 만들어야 합니다. 여기서는 Rescaling 레이어를 사용하여 값이 `[0, 1]`에 있도록 표준화합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "16yNdZXdExyM"
      },
      "outputs": [],
      "source": [
        "from tensorflow.keras import layers\n",
        "\n",
        "normalization_layer = tf.keras.layers.experimental.preprocessing.Rescaling(1./255)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Nd0_enkb8uxZ"
      },
      "source": [
        "이 레이어를 사용하는 방법에는 두 가지가 있습니다. map을 호출하여 데이터세트에 레이어를 적용할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QgOnza-U_z5Y"
      },
      "outputs": [],
      "source": [
        "normalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))\n",
        "image_batch, labels_batch = next(iter(normalized_ds))\n",
        "first_image = image_batch[0]\n",
        "# Notice the pixels values are now in `[0,1]`.\n",
        "print(np.min(first_image), np.max(first_image)) "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "z39nXayj9ioS"
      },
      "source": [
        "또는 모델 정의 내에 레이어를 포함하여 배포를 단순화할 수 있습니다. 여기서는 두 번째 접근 방식을 사용할 것입니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hXLd3wMpDIkp"
      },
      "source": [
        "참고: 픽셀 값을 `[-1,1]`으로 조정하려면 대신 `Rescaling(1./127.5, offset=-1)`를 작성할 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LeNWVa8qRBGm"
      },
      "source": [
        "참고: 이전에 `image_dataset_from_directory`의 `image_size` 인수를 사용하여 이미지 크기를 조정했습니다. 모델에 크기 조정 논리를 포함하려면 [Resizing](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/Resizing) 레이어를 대신 사용할 수 있습니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ti8avTlLofoJ"
      },
      "source": [
        "### 성능을 위한 데이터세트 구성하기\n",
        "\n",
        "버퍼링된 프리페치를 사용하여 I/O가 차단되지 않고 디스크에서 데이터를 생성할 수 있도록 합니다. 데이터를 로드할 때 사용해야 하는 두 가지 중요한 메서드입니다.\n",
        "\n",
        "`.cache()`는 첫 번째 epoch 동안 디스크에서 이미지를 로드한 후 이미지를 메모리에 유지합니다. 이렇게 하면 모델을 훈련하는 동안 데이터세트가 병목 상태가 되지 않습니다. 데이터세트가 너무 커서 메모리에 맞지 않는 경우, 이 메서드를 사용하여 성능이 높은 온디스크 캐시를 생성할 수도 있습니다.\n",
        "\n",
        "`.prefetch()`는 훈련 중에 데이터 전처리 및 모델 실행과 겹칩니다.\n",
        "\n",
        "관심 있는 독자는 [데이터 성능 가이드](https://www.tensorflow.org/guide/data_performance#prefetching)에서 두 가지 메서드와 디스크에 데이터를 캐시하는 방법에 대해 자세히 알아볼 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Ea3kbMe-pGDw"
      },
      "outputs": [],
      "source": [
        "AUTOTUNE = tf.data.experimental.AUTOTUNE\n",
        "\n",
        "train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)\n",
        "val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XqHjIr6cplwY"
      },
      "source": [
        "### 모델 훈련하기\n",
        "\n",
        "완전성을 위해 준비한 데이터세트를 사용하여 간단한 모델을 훈련하는 방법을 보여줍니다. 이 모델은 어떤 식으로든 조정되지 않았습니다. 목표는 방금 만든 데이터세트를 사용하여 역학을 보여주는 것입니다. 이미지 분류에 대한 자세한 내용은 이 [튜토리얼](https://www.tensorflow.org/tutorials/images/classification)을 참조하세요."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LdR0BzCcqxw0"
      },
      "outputs": [],
      "source": [
        "num_classes = 5\n",
        "\n",
        "model = tf.keras.Sequential([\n",
        "  layers.experimental.preprocessing.Rescaling(1./255),\n",
        "  layers.Conv2D(32, 3, activation='relu'),\n",
        "  layers.MaxPooling2D(),\n",
        "  layers.Conv2D(32, 3, activation='relu'),\n",
        "  layers.MaxPooling2D(),\n",
        "  layers.Conv2D(32, 3, activation='relu'),\n",
        "  layers.MaxPooling2D(),\n",
        "  layers.Flatten(),\n",
        "  layers.Dense(128, activation='relu'),\n",
        "  layers.Dense(num_classes)\n",
        "])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "t_BlmsnmsEr4"
      },
      "outputs": [],
      "source": [
        "model.compile(\n",
        "  optimizer='adam',\n",
        "  loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
        "  metrics=['accuracy'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ffwd44ldNMOE"
      },
      "source": [
        "참고: 몇 가지 epoch에 대해서만 훈련하므로 이 튜토리얼은 빠르게 진행됩니다. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "S08ZKKODsnGW"
      },
      "outputs": [],
      "source": [
        "model.fit(\n",
        "  train_ds,\n",
        "  batch_size=batch_size,\n",
        "  validation_data=val_ds,\n",
        "  epochs=3\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MEtT9YGjSAOK"
      },
      "source": [
        "참고: `model.fit`을 사용하는 대신 사용자 정의 훈련 루프를 작성할 수도 있습니다. 자세한 내용은 이 [튜토리얼](https://www.tensorflow.org/guide/keras/writing_a_training_loop_from_scratch)을 참조하세요."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BaW4wx5L7hrZ"
      },
      "source": [
        "검증 정확성이 훈련 정확성에 비해 낮으므로 모델이 과대적합되었음을 알 수 있습니다. 이 [튜토리얼](https://www.tensorflow.org/tutorials/keras/overfit_and_underfit)에서 과대적합 및 축소 방법에 대해 자세히 알아볼 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AxS1cLzM8mEp"
      },
      "source": [
        "## 미세 제어를 위해 tf.data 사용하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ylj9fgkamgWZ"
      },
      "source": [
        "위의 keras.preprocessing 유틸리티는 이미지의 디렉토리에서 `tf.data.Dataset`을 작성하는 편리한 방법입니다. 보다 세밀한 제어를 위해 `tf.data`을 사용하여 자체 입력 파이프라인을 작성할수 있습니다. 이 섹션에서는 이전에 다운로드한 zip 파일 경로부터 시작하여 이를 수행하는 방법을 보여줍니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "lAkQp5uxoINu"
      },
      "outputs": [],
      "source": [
        "list_ds = tf.data.Dataset.list_files(str(data_dir/'*/*'), shuffle=False)\n",
        "list_ds = list_ds.shuffle(image_count, reshuffle_each_iteration=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "coORvEH-NGwc"
      },
      "outputs": [],
      "source": [
        "for f in list_ds.take(5):\n",
        "  print(f.numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6NLQ_VJhWO4z"
      },
      "source": [
        "파일의 트리 구조를 사용하여 `class_names` 목록을 컴파일할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uRPHzDGhKACK"
      },
      "outputs": [],
      "source": [
        "class_names = np.array(sorted([item.name for item in data_dir.glob('*') if item.name != \"LICENSE.txt\"]))\n",
        "print(class_names)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CiptrWmAlmAa"
      },
      "source": [
        "데이터세트를 훈련 및 검증으로 분할합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GWHNPzXclpVr"
      },
      "outputs": [],
      "source": [
        "val_size = int(image_count * 0.2)\n",
        "train_ds = list_ds.skip(val_size)\n",
        "val_ds = list_ds.take(val_size)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rkB-IR4-pS3U"
      },
      "source": [
        "다음과 같이 각 데이터세트의 길이를 볼 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "SiKQrb9ppS-7"
      },
      "outputs": [],
      "source": [
        "print(tf.data.experimental.cardinality(train_ds).numpy())\n",
        "print(tf.data.experimental.cardinality(val_ds).numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "91CPfUUJ_8SZ"
      },
      "source": [
        "파일 경로를 `(img, label)` 쌍으로 변환하는 간단한 함수를 작성합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "arSQzIey-4D4"
      },
      "outputs": [],
      "source": [
        "def get_label(file_path):\n",
        "  # convert the path to a list of path components\n",
        "  parts = tf.strings.split(file_path, os.path.sep)\n",
        "  # The second to last is the class-directory\n",
        "  one_hot = parts[-2] == class_names\n",
        "  # Integer encode the label\n",
        "  return tf.argmax(one_hot)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MGlq4IP4Aktb"
      },
      "outputs": [],
      "source": [
        "def decode_img(img):\n",
        "  # convert the compressed string to a 3D uint8 tensor\n",
        "  img = tf.image.decode_jpeg(img, channels=3)\n",
        "  # resize the image to the desired size\n",
        "  return tf.image.resize(img, [img_height, img_width])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-xhBRgvNqRRe"
      },
      "outputs": [],
      "source": [
        "def process_path(file_path):\n",
        "  label = get_label(file_path)\n",
        "  # load the raw data from the file as a string\n",
        "  img = tf.io.read_file(file_path)\n",
        "  img = decode_img(img)\n",
        "  return img, label"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "S9a5GpsUOBx8"
      },
      "source": [
        "`Dataset.map`을 사용하여 `image, label` 쌍의 데이터세트를 작성합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3SDhbo8lOBQv"
      },
      "outputs": [],
      "source": [
        "# Set `num_parallel_calls` so multiple images are loaded/processed in parallel.\n",
        "train_ds = train_ds.map(process_path, num_parallel_calls=AUTOTUNE)\n",
        "val_ds = val_ds.map(process_path, num_parallel_calls=AUTOTUNE)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kxrl0lGdnpRz"
      },
      "outputs": [],
      "source": [
        "for image, label in train_ds.take(1):\n",
        "  print(\"Image shape: \", image.numpy().shape)\n",
        "  print(\"Label: \", label.numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vYGCgJuR_9Qp"
      },
      "source": [
        "### 성능을 위한 데이터세트 구성하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wwZavzgsIytz"
      },
      "source": [
        "이 데이터세트로 모델을 훈련하려면 데이터에 대해 다음이 필요합니다.\n",
        "\n",
        "- 잘 섞는다.\n",
        "- 배치 처리한다.\n",
        "- 가능한 빨리 배치를 사용할 수 있어야 한다.\n",
        "\n",
        "이러한 기능은 `tf.data` API를 사용하여 추가할 수 있습니다. 자세한 내용은 [입력 파이프라인 성능](../../guide/performance/datasets) 가이드를 참조하세요."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uZmZJx8ePw_5"
      },
      "outputs": [],
      "source": [
        "def configure_for_performance(ds):\n",
        "  ds = ds.cache()\n",
        "  ds = ds.shuffle(buffer_size=1000)\n",
        "  ds = ds.batch(batch_size)\n",
        "  ds = ds.prefetch(buffer_size=AUTOTUNE)\n",
        "  return ds\n",
        "\n",
        "train_ds = configure_for_performance(train_ds)\n",
        "val_ds = configure_for_performance(val_ds)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "45P7OvzRWzOB"
      },
      "source": [
        "### 데이터 시각화하기\n",
        "\n",
        "이 데이터세트를 이전에 작성한 데이터세트와 유사하게 시각화할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UN_Dnl72YNIj"
      },
      "outputs": [],
      "source": [
        "image_batch, label_batch = next(iter(train_ds))\n",
        "\n",
        "plt.figure(figsize=(10, 10))\n",
        "for i in range(9):\n",
        "  ax = plt.subplot(3, 3, i + 1)\n",
        "  plt.imshow(image_batch[i].numpy().astype(\"uint8\"))\n",
        "  label = label_batch[i]\n",
        "  plt.title(class_names[label])\n",
        "  plt.axis(\"off\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fMT8kh_uXPRU"
      },
      "source": [
        "### 모델 계속 훈련하기\n",
        "\n",
        "위의 `keras.preprocessing`에 의해 작성된 것과 유사한 `tf.data.Dataset`를 수동으로 빌드했습니다. 모델 훈련을 계속할 수 있습니다. 이전과 마찬가지로 실행 시간을 짧게 유지하기 위해 몇 가지 epoch 동안 훈련합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Vm_bi7NKXOzW"
      },
      "outputs": [],
      "source": [
        "model.fit(\n",
        "  train_ds,\n",
        "  validation_data=val_ds,\n",
        "  epochs=3\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EDJXAexrwsx8"
      },
      "source": [
        "## TensorFlow 데이터세트 사용하기\n",
        "\n",
        "이 튜토리얼에서는 지금까지 디스크에서 데이터를 로드하는 데 중점을 두었습니다. [TensorFlow 데이터세트](https://www.tensorflow.org/datasets)에서 다운로드하기 쉬운 대규모 데이터세트 [카탈로그](https://www.tensorflow.org/datasets)를 탐색하여 사용할 데이터세트를 찾을 수도 있습니다. 이전에 Flowers 데이터세트를 디스크에서 로드했으므로 TensorFlow 데이터세트로 가져오는 방법을 살펴보겠습니다. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Qyu9wWDf1gfH"
      },
      "source": [
        "TensorFlow 데이터세트를 사용하여 꽃 [데이터세트](https://www.tensorflow.org/datasets/catalog/tf_flowers)를 다운로드합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NTQ-53DNwv8o"
      },
      "outputs": [],
      "source": [
        "(train_ds, val_ds, test_ds), metadata = tfds.load(\n",
        "    'tf_flowers',\n",
        "    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],\n",
        "    with_info=True,\n",
        "    as_supervised=True,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3hxXSgtj1iLV"
      },
      "source": [
        "꽃 데이터세트에는 5개의 클래스가 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kJvt6qzF1i4L"
      },
      "outputs": [],
      "source": [
        "num_classes = metadata.features['label'].num_classes\n",
        "print(num_classes)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6dbvEz_F1lgE"
      },
      "source": [
        "데이터세트에서 이미지를 검색합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1lF3IUAO1ogi"
      },
      "outputs": [],
      "source": [
        "get_label_name = metadata.features['label'].int2str\n",
        "\n",
        "image, label = next(iter(train_ds))\n",
        "_ = plt.imshow(image)\n",
        "_ = plt.title(get_label_name(label))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lHOOH_4TwaUb"
      },
      "source": [
        "이전과 마찬가지로, 성능을 위해 각 데이터세트를 일괄 처리, 셔플 및 구성해야 합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AMV6GtZiwfGP"
      },
      "outputs": [],
      "source": [
        "train_ds = configure_for_performance(train_ds)\n",
        "val_ds = configure_for_performance(val_ds)\n",
        "test_ds = configure_for_performance(test_ds)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gmR7kT8l1w20"
      },
      "source": [
        "[데이터 강화](https://www.tensorflow.org/tutorials/images/data_augmentation) 가이드를 방문하여 꽃 데이터세트 및 TensorFlow 데이터세트를 처리하는 전체 예제를 찾을 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6cqkPenZIaHl"
      },
      "source": [
        "## 다음 단계\n",
        "\n",
        "이 튜토리얼에서는 디스크에서 이미지를 로드하는 두 가지 방법을 보여주었습니다. 먼저 Keras 전처리 레이어 및 유틸리티를 사용하여 이미지 데이터세트를 로드하고 전처리하는 방법을 배웠습니다. 다음으로, tf.data를 사용하여 처음부터 입력 파이프라인을 작성하는 방법을 배웠습니다. 다음 단계로 이 [튜토리얼](https://www.tensorflow.org/tutorials/images/data_augmentation)을 방문하여 데이터 기능 보강을 추가하는 방법을 학습할 수 있습니다. tf.data에 대한 자세한 내용은 이 [가이드](https://www.tensorflow.org/guide/data)를 참조하세요."
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [],
      "name": "images.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
